//TerrainPatch.h
//Created 28/01/14
//Cretaed By Daniel Bowler
//
//Represents a single patch in the terrain system. 
//
//Modified: 28/02/14 - Generates a medium quality patch - used when rendering
//patches that are far away to save on the verticies. 

#pragma once

//This is an advanced model. . 
#include "AbstractAdvancedModel.h"

//include our terrain effect - enables us to access the per vertex structure
//in this header.
#include "TerrainFX.h"

//Defines how many times we scale a texture across a single patch. We will
//divide the size by this value. 
#define TERRAIN_PATCH_TEX_TRANS_DIV 10.0f
//Defines how many times we scale a detail texture across a single patch. 
//As above, we divide the size by this value
#define TERRAIN_PATCH_DETAIL_TEX_TRANS_DIV 4.0f

//When the patch is X units from the camera, render the med quality patch - If the gen
//med quality define is commented, we wont create nor use the medium quality
//model. 
#define TERRAIN_PATCH_GEN_MED_QUALITY
#define TERRAIN_PATCH_MED_QUALITY_RANGE 50000.0f

//POM Min and maximum samples. Higher values result in poorer perfromance but
//less aliasing issues
#define TERRAIN_POM_MIN_SAMPLES 10
#define TERRAIN_POM_MAX_SAMPLES 65

//POM height scales - one per layer texture (not the underlays as they wont be rendered
//with POM as they look... crap)
#define TERRAIN_POM_HEIGHT_0_SCALE 0.09f
#define TERRAIN_POM_HEIGHT_1_SCALE 0.02f 
#define TERRAIN_POM_HEIGHT_2_SCALE 0.07f

//A structure which represents the textures for each patch. Note that some patches will
//share the same texture resources, but each patch needs its own pointer to them. 
//
//The terrain class will fillout one of these per patch and pass it to the Init
//functions. Note that the terrain class will be responsable for loading the textures
//and therefore destroying the textures. 
struct TerrainPatchTextureData
{
	TerrainPatchTextureData()
	{
		//Init pointers to NULL
		DiffuseMap0 = 0;
		DetailMap0 = 0;
		NormalMap0 = 0;
		DiffuseMap1 = 0;
		DiffuseMap2 = 0;
		NormalMap1 = 0;
		NormalMap2 = 0;

		HeightMap0 = 0;
		HeightMap1 = 0;
		HeightMap2 = 0;

		SpecMap0 = 0;
		SpecMap1 = 0;
		SpecMap2 = 0;

		//Layer map data
		LayerMap1 = 0;

		//Layer texture data
		Layer1Tex = 0;
		Layer1Normal = 0;
		Layer1Spec = 0;
		Layer1Height = 0;
	}
	~TerrainPatchTextureData()
	{
		//Destroy D3D resources.
		ReleaseCOM(DiffuseMap0);
		ReleaseCOM(DetailMap0);
		ReleaseCOM(NormalMap0);
		ReleaseCOM(DiffuseMap1);
		ReleaseCOM(DiffuseMap2);
		ReleaseCOM(NormalMap1);
		ReleaseCOM(NormalMap2);

		ReleaseCOM(HeightMap0);
		ReleaseCOM(HeightMap1);
		ReleaseCOM(HeightMap2);

		ReleaseCOM(SpecMap0);
		ReleaseCOM(SpecMap1);
		ReleaseCOM(SpecMap2);

		//Layer data
		ReleaseCOM(LayerMap1);

		//Layer tex data
		ReleaseCOM(Layer1Tex);
		ReleaseCOM(Layer1Normal);
		ReleaseCOM(Layer1Spec);
		ReleaseCOM(Layer1Height);
	}

	//Resources:
	//
	//Diffuse Maps:
	ID3D11ShaderResourceView* DiffuseMap0;
	ID3D11ShaderResourceView* DiffuseMap1;
	ID3D11ShaderResourceView* DiffuseMap2;

	//Detail map - Used on fragments that are close to the camera to provide
	//added detail. 
	ID3D11ShaderResourceView* DetailMap0;

	//Normal Maps. 
	ID3D11ShaderResourceView* NormalMap0;
	ID3D11ShaderResourceView* NormalMap1;
	ID3D11ShaderResourceView* NormalMap2;

	//Height maps (POM)
	ID3D11ShaderResourceView* HeightMap0;
	ID3D11ShaderResourceView* HeightMap1;
	ID3D11ShaderResourceView* HeightMap2;

	//Specular maps
	ID3D11ShaderResourceView* SpecMap0;
	ID3D11ShaderResourceView* SpecMap1;
	ID3D11ShaderResourceView* SpecMap2;

	//Layer maps (greyscale)
	ID3D11ShaderResourceView* LayerMap1;

	//Layer texture data (colour / norm, etc)
	ID3D11ShaderResourceView* Layer1Tex;
	ID3D11ShaderResourceView* Layer1Normal;
	ID3D11ShaderResourceView* Layer1Spec;
	ID3D11ShaderResourceView* Layer1Height;
};

class TerrainPatch : public AbstractAdvancedModel
{
	//We want our Terrain high level class to access the private stuff - eg AABB. 
	friend class Terrain;
	//Also want water to acess data (mini hack)
	friend class TerrainWater;
public:
	//Standard constructor and destructor
	TerrainPatch();
	~TerrainPatch();

private:
	//Inits the terrain - 24 bit BMP. 
	void Init(ID3D11Device* device, 
		const char* heightMapFile,				 //Height map texture location
		bool isPNG,                              //PNG File (16 bit - else 24 bit bmp)
		float terrainCellSize,                   //How large is each cell. Stick to 1.0f imo.
		TerrainPatchTextureData *texData,        //Texture data (Preloaded)
		float heightDivFactor,					 //Reduce the sampled heights .
		bool isSlopeBasedTerrain = true,         //Slope Based Rendering
		float height1 = 0.0f, float height2 = 0.0f); //If using height based rendering

	//Alternative method to init the terrain patch - here, the height of each vertex
	//has been precomputed. 
	void InitAdvanced(ID3D11Device* device, 
		std::vector<float>&heights,              //Heights for every vertex
		std::vector<float>&medHeights,           //Medium heights. 
		float width, float depth,                //size of patch. 
		float terrainCellSize,                   //How large is each cell. Stick to 1.0f imo.
		TerrainPatchTextureData* texData,		 //Texture Data (Preloaded).
		float texStepSizeX, float texStepSizeY,				//For layer map - how much to incremenet tex coord per vertex. 
		float minLayerTexCoordX, float minLayerTexCoordY,   //For layer map - tex coord of top left vertex
		bool isSlopeBasedterrain = true,         //Slope Based Rendering
		float height1 = 0.0f, float height2 = 0.0f); //If using height based rendering

private:
	//Called by Graphics Interface - this then calls the render functions
	//for each layer. 
	void Render(bool isZPrePass, bool isOpaquePass, bool isShadowPass,		   //Flags telling us what pass it is. 
		VirtualCamera* playerCamera,										   //Player camera - passed from GraphicsInterface
		DirecLightShadowMapData* shadowMap,									   //Single shadow map - passed from GraphicsInterface. 
		SSAOData* ssaoMap,													   //SSAO Map.
		ID3D11ShaderResourceView* envMap,									   //Environment map. 
		ID3D11ShaderResourceView* llb,                                         //Light list buffer - gloabl set of lights. 
		ID3D11ShaderResourceView* llibO, ID3D11ShaderResourceView* llsebO,     //Opaque Tile Based Forward buffers. 
		ID3D11ShaderResourceView* llibT, ID3D11ShaderResourceView* llsebT,     //Transparant pass. 
		DirectionalLight* dLightArr, unsigned dLightCount,					   //Directional lights and light count. 
		XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange,						   //Hemispherical ambient lighting data.
		CXMMATRIX &view, CXMMATRIX &proj,									   //Cameras view/proj or the shadow maps view/proj depending on the pass. 
		ID3D11DeviceContext* context);										   //Context we are rendeirng through. 

private:
	//Terrain (grid) VB and IB - this is the data of the buffer we displace - High quality 
	ID3D11Buffer* terrainLayerVB;
	ID3D11Buffer* terrainLayerIB;

	//Med quality
	ID3D11Buffer* terrainLayerMedVB;
	ID3D11Buffer* terrainLayerMedIB;

	//Draw count for the terrain layer
	unsigned terrainLayerDrawCount;
	unsigned terrainLayerMedDrawCount;

	//Terrain (grid) material.
	Material terrainMaterial;

	//Texture matricies
	XMFLOAT4X4 terrainTexTrans;
	XMFLOAT4X4 terrainTexDetailTrans;

	//Terrain texture data - struct which can contain multiple textures. 
	TerrainPatchTextureData* terrainTexData;

	//Flag indicating which mode we are rendering with (slope or height based)
	bool useSlopeBasedRendering;
	//If using slope based rendeirng, these are the height factors for the patch
	float heightFac1;
	float heightFac2;

private:
	//Terrain dimentions (Verticies)
	float terrainWidth;
	float terrainDepth;

	//Terrain cell size - with this, we can work out the size (world space units)
	//of the terrain patch. 
	float terrainCellSize;

private:
	//Loads the height map and obtains the height for every vertex - 24bit .bmp file.This function
	//also reads the bmp header and works out how large the terrain is. 
	void LoadHeightMap(ID3D11Device* device, std::vector<float>&heightsOut, 
		const char* filename);
	//Used for RAW files. 8 bit. 
	void LoadHeightMapRAW8(ID3D11Device* device, std::vector<float>&heightsOut, 
		const char* filename);
	//16 bit raw
	void LoadHeightMapRAW16(ID3D11Device* device, std::vector<float>&heightsOut, 
		const char* filename);
	//Used for PNG files. 16 bit
	void LoadHeightMapPNG(ID3D11Device* device, std::vector<float>&heightsOut, 
		const char* filename);

	//Normalizes the height map so the values are not as dramatic. 
	void ScaleHeightMap(std::vector<float>&height, float factor);

	//Create the grid using the geometry generator. We then displace each vertex
	//based on the heightmap. 
	void CreateGrid(ID3D11Device* device, std::vector<float>&heights, 
		float minTexCoordX, float minTexCoordY, 
		float texCoordStepX, float texCoordStepY);

	//Generates the face normal vectors for each vertex in the grid. Called inside
	//CreateGrid() but before creating the VB
	void GenerateNormals(std::vector<TerrainFX::PerVertex>&verts, 
		std::vector<UINT>&inds);
	//Generates tangent vectors (Must be called after GenNormals())
	void GenerateTangents(std::vector<TerrainFX::PerVertex>&verts, 
		std::vector<UINT>&inds);

	//Generates a medium poly version of the patch - LOD rendering.
	void GenerateMedQualityTerrain(ID3D11Device* device, 
		std::vector<float>&heights);
};